package com.ikas.ai.server.module.morningpaper.service;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.consts.MachineAndWorkConditionConst;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.cockpit.model.dto.StartCountStatisticsDTO;
import com.ikas.ai.server.module.data.service.DorisYcDataService;
import com.ikas.ai.server.module.morningpaper.consts.MorningPaperConditionWholeYearVariableNames;
import com.ikas.ai.server.module.morningpaper.consts.MorningPaperFailRecordVariableNames;
import com.ikas.ai.server.module.morningpaper.consts.MorningPaperNormalVariableNames;
import com.ikas.ai.server.module.morningpaper.consts.MorningPaperOverhaulVariableNames;
import com.ikas.ai.server.module.morningpaper.dao.MorningPaperHisDao;
import com.ikas.ai.server.module.morningpaper.dao.MorningPaperVariablesDao;
import com.ikas.ai.server.module.morningpaper.exception.MorningPaperException;
import com.ikas.ai.server.module.morningpaper.model.dto.FailureRecord;
import com.ikas.ai.server.module.morningpaper.model.dto.MorningPaperExcelDTO;
import com.ikas.ai.server.module.morningpaper.model.dto.MorningPaperVariablesDto;
import com.ikas.ai.server.module.morningpaper.model.elements.ElementMachinePriority;
import com.ikas.ai.server.module.morningpaper.model.po.MorningPaperHisPo;
import com.ikas.ai.server.module.morningpaper.model.po.MorningPaperVariablesPo;
import com.ikas.ai.server.module.morningpaper.render.MorningPaperVariablesRender;
import com.ikas.ai.server.module.morningpaper.util.MorningPaperTimeUtil;
import com.ikas.ai.server.module.system.model.User;
import com.ikas.ai.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author li.hexian
 * t_morning_paper_variable变量表相关接口及工具<主要>
 */
@Service
@Slf4j
public class MorningPaperVariablesService extends ServiceImpl<MorningPaperVariablesDao, MorningPaperVariablesPo> {

    @Autowired
    MorningPaperOverhaulPlanService morningPaperOverhaulPlanService;
    @Autowired
    MorningPaperVariablesRender morningPaperVariablesRender;
    @Autowired
    MorningPaperHisService morningPaperHisService;
    @Autowired
    DorisYcDataService dorisYcDataService;
    @Autowired
    MorningPaperTimeUtil morningPaperTimeUtil;
    @Autowired
    private MorningPaperVariablesDao morningPaperVariablesDao;
    @Autowired
    private FailureRecordService failureRecordService;
    @Autowired
    private MorningPaperHisDao morningPaperHisDao;

    private static final String dateStr = "1970-01-01 00:00:00";


    /**
     * === MAIN METHODS ===
     */

    /**
     * 获取早报DTO主方法
     *
     * @return
     */
    public MorningPaperVariablesDto get() {
        int count = count(
                new LambdaQueryWrapper<MorningPaperVariablesPo>().eq(MorningPaperVariablesPo::getDate, morningPaperTimeUtil.getYesterdayDayDate())
        );
        MorningPaperVariablesDto mv;
        if (count > 0) {
            /**
             * 如果数据库中已经有当天生成的早报，直接返回变量表里的所有变量
             */
            mv = getOneAlreadyExist();
        } else {
            /**
             * 如果数据库中没有当天生成的早报，则报错
             */
            throw new MorningPaperException(MorningPaperException.morningPaperNotGenerate);
        }
        return mv;
    }

    /**
     * update variables表内的变量，不包含以下：
     * 1.检修记录
     * 2.失败记录
     *
     * @param mv
     * @param posMap
     */
    @Transactional(rollbackFor = Exception.class)
    public MorningPaperVariablesDto refresh(MorningPaperVariablesDto mv, Map<String, MorningPaperVariablesPo> posMap) {
        log.info("update-t_morning_paper_variables:{}--{}", JSON.toJSONString(mv), JSON.toJSONString(posMap));
        updateBatchById(fillPoList(removeUnnecessaryInRefresh(BeanUtil.beanToMap(mv)), posMap));
        //更新完成之后再更新成功率
        updateSuccessPercent(mv);
        return this.get();
    }

    public void updateSuccessPercent(MorningPaperVariablesDto mv) {
        Map<String, MorningPaperVariablesPo> posMap = getPosMap();
        Map<String, Long> statistics = failureRecordService.statistics(DateUtil.year(new Date()));
        Long gFailCount = statistics.get(MachineAndWorkConditionConst.CONDITION_G);
        Long gSuccessCount = mv.getConditionGInWholeYearCount();
        MorningPaperVariablesPo morningPaperVariablesPo1 = posMap.get(MorningPaperConditionWholeYearVariableNames.conditionGInWholeYearSuccessPercent.name());
        buildPercent(gFailCount, gSuccessCount, morningPaperVariablesPo1);
        posMap.put(MorningPaperConditionWholeYearVariableNames.conditionGInWholeYearSuccessPercent.name(), morningPaperVariablesPo1);

        Long pFailCount = statistics.get(MachineAndWorkConditionConst.CONDITION_P);
        Long pSuccessCount = mv.getConditionPInWholeYearCount();
        MorningPaperVariablesPo morningPaperVariablesPo2 = posMap.get(MorningPaperConditionWholeYearVariableNames.conditionPInWholeYearSuccessPercent.name());
        buildPercent(pFailCount, pSuccessCount, morningPaperVariablesPo2);
        posMap.put(MorningPaperConditionWholeYearVariableNames.conditionPInWholeYearSuccessPercent.name(), morningPaperVariablesPo2);

        Long failCount = statistics.get(MachineAndWorkConditionConst.CONDITION_PC);
        Long successCount = mv.getConditionPCInWholeYearCount();
        MorningPaperVariablesPo morningPaperVariablesPo3 = posMap.get(MorningPaperConditionWholeYearVariableNames.conditionPCInWholeYearSuccessPercent.name());
        buildPercent(failCount, successCount, morningPaperVariablesPo3);
        posMap.put(MorningPaperConditionWholeYearVariableNames.conditionPCInWholeYearSuccessPercent.name(), morningPaperVariablesPo3);

        updateBatchById(posMap.values());
    }

    private void buildPercent(Long failCount, Long successCount, MorningPaperVariablesPo morningPaperVariablesPo) {
        if (Objects.isNull(successCount) || successCount == 0) {
            morningPaperVariablesPo.setValue("0");
        } else if (Objects.isNull(failCount) || failCount == 0) {
            morningPaperVariablesPo.setValue("1");
        } else {
            double percent = BigDecimal.valueOf(successCount).divide(BigDecimal.valueOf(failCount + successCount), 2, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP).doubleValue();
            morningPaperVariablesPo.setValue(String.valueOf(percent));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void save(MorningPaperVariablesDto mv, Map<String, MorningPaperVariablesPo> posMap) {
        log.info("save-t_morning_paper_variables:{}--{}", JSON.toJSONString(mv), JSON.toJSONString(posMap));
        //定时任务统计，先删除今天跑的昨天的日报的再保存
        QueryWrapper<MorningPaperVariablesPo> wrapper = new QueryWrapper<>();
        wrapper.eq("date", morningPaperTimeUtil.getYesterdayDayDate());
        morningPaperVariablesDao.delete(wrapper);
        saveBatch(fillPoList(removeUnnecessaryInRefresh(BeanUtil.beanToMap(mv)), posMap));
        updateSuccessPercent(mv);
    }

    /**
     * 从variables及相关表读取变量并拼装一个MorningPaperVariablesDto返回
     * 以下变量不直接从variables表中加载：
     * 1.检修信息
     * 以下variables中的内容不存入MorningPaperVariablesDto中:
     * 1.设备全年失败记录
     *
     * @return MorningPaperVariableDto
     */
    private MorningPaperVariablesDto getOneAlreadyExist() {
        //获取最新一天所有变量map
        LambdaQueryChainWrapper<MorningPaperVariablesPo> wrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
        MorningPaperVariablesPo paperVariablesPo = wrapper.orderByDesc(MorningPaperVariablesPo::getDate).list().get(0);
        Date date = paperVariablesPo.getDate();
        LambdaQueryChainWrapper<MorningPaperVariablesPo> listWrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
        List<MorningPaperVariablesPo> list = listWrapper.eq(MorningPaperVariablesPo::getDate, date)
                .list();
        Map<String, String> variablesMap = removeFailRecords(
                putOverhaulDetail(
                        list.stream().collect(Collectors.toMap(MorningPaperVariablesPo::getVariableName, MorningPaperVariablesPo::getValue))
                )
        );
        return BeanUtil.mapToBean(variablesMap, MorningPaperVariablesDto.class, null);
    }


    /**
     * === TOOLS ===
     */

    /**
     * 获取所有变量组成的MAP
     *
     * @return
     */
    public Map<String, MorningPaperVariablesPo> getPosMap() {
        //获取最新一天所有变量map
        LambdaQueryChainWrapper<MorningPaperVariablesPo> wrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
        List<MorningPaperVariablesPo> morningPaperVariablesPos = wrapper.orderByDesc(MorningPaperVariablesPo::getDate).list();
        MorningPaperNormalVariableNames[] values = MorningPaperNormalVariableNames.values();
        List<MorningPaperVariablesPo> list;
        if (CollectionUtils.isEmpty(morningPaperVariablesPos)) {
            for (MorningPaperNormalVariableNames value : values) {
                MorningPaperVariablesPo morningPaperVariablesPo = new MorningPaperVariablesPo();
                morningPaperVariablesPo.setVariableName(value.name());
                if (MorningPaperNormalVariableNames.machinePriority.name().equals(value.name())) {
                    morningPaperVariablesPo.setValue(ElementMachinePriority.ONE_TWO_THREE_FOUR);
                } else {
                    morningPaperVariablesPo.setValue("1");
                }
                morningPaperVariablesPo.setDate(DateTime.of(dateStr, DateTimeUtil.DATETIMEFORMATTPL));
                morningPaperVariablesPo.setUpdateTime(new Date());
                morningPaperVariablesPo.setMeteCode(value.getMeteCode());
                morningPaperVariablesPo.setMeteId(value.getMeteId());
                morningPaperVariablesPo.setDescription(value.getDesc());
                morningPaperVariablesPos.add(morningPaperVariablesPo);
            }
            list = morningPaperVariablesPos;
        } else {
            Date date = morningPaperVariablesPos.get(0).getDate();
            LambdaQueryChainWrapper<MorningPaperVariablesPo> listWrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
            list = listWrapper.eq(MorningPaperVariablesPo::getDate, date).list();
            list.forEach(i -> {
                MorningPaperNormalVariableNames po = MorningPaperNormalVariableNames.getByCode(i.getVariableName());
                if (Objects.nonNull(po)) {
                    i.setMeteId(po.getMeteId());
                    i.setMeteCode(po.getMeteCode());
                }
            });
        }
        return list.stream().collect(Collectors.toMap(MorningPaperVariablesPo::getVariableName, bean -> bean));
    }

    /**
     * 放入检修信息
     *
     * @param variablesMap
     * @return
     */
    private Map<String, String> putOverhaulDetail(Map<String, String> variablesMap) {
        variablesMap.putAll(morningPaperOverhaulPlanService.getAllMachineOverhaulInfo());
        return variablesMap;
    }

    /**
     * 移除在update操作中不必要的字段
     *
     * @param variablesMap
     * @return
     */
    private Map removeUnnecessaryInRefresh(Map variablesMap) {
        variablesMap = removeFailRecords(variablesMap);
        variablesMap = removeOverhaulDetails(variablesMap);
        return variablesMap;
    }

    /**
     * 移除失败记录信息
     *
     * @param variablesMap
     * @return
     */
    private Map removeFailRecords(Map variablesMap) {
        MorningPaperFailRecordVariableNames[] values = MorningPaperFailRecordVariableNames.values();
        for (MorningPaperFailRecordVariableNames failRecordVariableName : values) {
            String name = failRecordVariableName.name();
            variablesMap.remove(name);
        }
        return variablesMap;
    }

    /**
     * 移除检修记录
     *
     * @param variablesMap
     * @return
     */
    private Map removeOverhaulDetails(Map variablesMap) {
        MorningPaperOverhaulVariableNames[] values = MorningPaperOverhaulVariableNames.values();
        for (MorningPaperOverhaulVariableNames failRecordVariableName : values) {
            String name = failRecordVariableName.name();
            variablesMap.remove(name);
        }
        return variablesMap;
    }


    private final String NULL_VALUE = "null";

    public List<MorningPaperVariablesPo> fillPoList(Map<String, Object> stringObjectMap, Map<String, MorningPaperVariablesPo> posMap) {
        List<MorningPaperVariablesPo> variablesCollect = stringObjectMap.entrySet().stream().map(variable -> {
            String variableName = variable.getKey();
            Object value = variable.getValue();
            MorningPaperVariablesPo morningPaperVariablesPo = new MorningPaperVariablesPo();
            morningPaperVariablesPo.setVariableName(variableName);
            if (!NULL_VALUE.equals(value) && value != null) {
                morningPaperVariablesPo.setValue(String.valueOf(value));
            } else {
                morningPaperVariablesPo.setValue("");
            }
            morningPaperVariablesPo.setUpdateTime(new Date());
            // 获取前一天的日期时间
            morningPaperVariablesPo.setDate(morningPaperTimeUtil.getYesterdayDayDate());
            if (Objects.nonNull(posMap.get(variableName).getId())) {
                morningPaperVariablesPo.setId(posMap.get(variableName).getId());
            }
            MorningPaperNormalVariableNames name = MorningPaperNormalVariableNames.getByCode(variableName);
            if (Objects.nonNull(name)) {
                morningPaperVariablesPo.setMeteCode(name.getMeteCode());
                morningPaperVariablesPo.setMeteId(name.getMeteId());
                morningPaperVariablesPo.setDescription(name.getDesc());
            } else {
                morningPaperVariablesPo.setDescription(variableName);
            }
            return morningPaperVariablesPo;
        }).collect(Collectors.toList());
        log.info("更新变量集合:{}", JSON.toJSONString(variablesCollect));
        return variablesCollect;
    }

    public StartCountStatisticsDTO startCountStatistics(String startDate, String endDate, Integer type) {
        if (DateUtil.compare(new Date(), DateUtil.parseDate(startDate)) < 0) {
            throw new BusinessException("查询起始时间不能大于当前时间");
        }
        // 2024-03-04 -> 2024-03-11
        // 驾驶舱单独的数据需要查询出所有的相加，总数据查询每个时间段的最新数据作为总次数总时长等
        LambdaQueryChainWrapper<MorningPaperVariablesPo> wrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
        List<MorningPaperVariablesPo> morningPaperVariablesPoList = wrapper
                .ge(StringUtils.isNotBlank(startDate), MorningPaperVariablesPo::getDate, startDate)
                .lt(StringUtils.isNotBlank(endDate), MorningPaperVariablesPo::getDate, endDate)
                .orderByDesc(MorningPaperVariablesPo::getDate)
                .list();
        StartCountStatisticsDTO startCountStatisticsDTO = new StartCountStatisticsDTO();
        startCountStatisticsDTO.setMachineU01GStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionGPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU01PStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionPPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU01PCStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionPCPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU02GStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionGPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU02PStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionPPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU02PCStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionPCPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU03GStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionGPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU03PStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionPPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU03PCStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionPCPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU04GStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionGPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU04PStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionPPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());
        startCountStatisticsDTO.setMachineU04PCStartCount(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionPCPowerUpCount.name().equals(i.getVariableName())).mapToInt(i -> Integer.parseInt(i.getValue())).sum());

        startCountStatisticsDTO.setMachineU01GRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionGPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU01PRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionPPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU01PCRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU01ConditionPCPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU02GRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionGPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU02PRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionPPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU02PCRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU02ConditionPCPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU03GRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionGPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU03PRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionPPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU03PCRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU03ConditionPCPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU04GRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionGPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU04PRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionPPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setMachineU04PCRuntime(Math.abs(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machineU04ConditionPCPowerUpHours.name().equals(i.getVariableName())).map(i -> new BigDecimal(i.getValue())).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue()));
        startCountStatisticsDTO.setTotalGRuntime(Math.abs(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU01GRuntime()).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU02GRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU03GRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU04GRuntime())).doubleValue()));
        startCountStatisticsDTO.setTotalPRuntime(Math.abs(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU01PRuntime()).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU02PRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU03PRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU04PRuntime())).doubleValue()));
        startCountStatisticsDTO.setTotalPCRuntime(Math.abs(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU01PCRuntime()).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU02PCRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU03PCRuntime())).add(BigDecimal.valueOf(startCountStatisticsDTO.getMachineU04PCRuntime())).doubleValue()));
        if (Objects.nonNull(type) && type == 3) {
            //如果查询的某年，需要取集合的最后一条数据，取全年的次数，成功率，运行时长等
            if (CollectionUtils.isNotEmpty(morningPaperVariablesPoList)) {
                startCountStatisticsDTO.setTotalGCount(Integer.valueOf(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionGInWholeYearCount.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()));
                startCountStatisticsDTO.setTotalPCount(Integer.valueOf(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionPInWholeYearCount.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()));
                startCountStatisticsDTO.setTotalPCCount(Integer.valueOf(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionPCInWholeYearCount.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()));
                startCountStatisticsDTO.setTotalCount(Integer.valueOf(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.machinePowerUpInWholeYearCount.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()));
                startCountStatisticsDTO.setGSuccessPercent(new BigDecimal(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionGInWholeYearSuccessPercent.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()).multiply(BigDecimal.valueOf(100)).doubleValue());
                startCountStatisticsDTO.setPSuccessPercent(new BigDecimal(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionPInWholeYearSuccessPercent.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()).multiply(BigDecimal.valueOf(100)).doubleValue());
                startCountStatisticsDTO.setPcSuccessPercent(new BigDecimal(morningPaperVariablesPoList.stream().filter(i -> MorningPaperNormalVariableNames.conditionPCInWholeYearSuccessPercent.name().equals(i.getVariableName())).findFirst().orElse(new MorningPaperVariablesPo()).getValue()).multiply(BigDecimal.valueOf(100)).doubleValue());
            }
        } else {
            //总次数应该查询最新的一条，早报修改也是修改最新一条
            startCountStatisticsDTO.setTotalGCount(startCountStatisticsDTO.getMachineU01GStartCount() + startCountStatisticsDTO.getMachineU02GStartCount() + startCountStatisticsDTO.getMachineU03GStartCount() + startCountStatisticsDTO.getMachineU04GStartCount());
            startCountStatisticsDTO.setTotalPCount(startCountStatisticsDTO.getMachineU01PStartCount() + startCountStatisticsDTO.getMachineU02PStartCount() + startCountStatisticsDTO.getMachineU03PStartCount() + startCountStatisticsDTO.getMachineU04PStartCount());
            startCountStatisticsDTO.setTotalPCCount(startCountStatisticsDTO.getMachineU01PCStartCount() + startCountStatisticsDTO.getMachineU02PCStartCount() + startCountStatisticsDTO.getMachineU03PCStartCount() + startCountStatisticsDTO.getMachineU04PCStartCount());
            startCountStatisticsDTO.setTotalCount(startCountStatisticsDTO.getTotalGCount() + startCountStatisticsDTO.getTotalPCount() + startCountStatisticsDTO.getTotalPCCount());
            //查找失败次数
            List<FailureRecord> failureRecords = failureRecordService.list(startDate, endDate);
            int gFailCount = Math.toIntExact(failureRecords.stream().filter(i -> MachineAndWorkConditionConst.CONDITION_G.equals(i.getFailureFw())).count());
            int pFailCount = Math.toIntExact(failureRecords.stream().filter(i -> MachineAndWorkConditionConst.CONDITION_P.equals(i.getFailureFw())).count());
            int pcFailCount = Math.toIntExact(failureRecords.stream().filter(i -> MachineAndWorkConditionConst.CONDITION_PC.equals(i.getFailureFw())).count());
            double gPercent = BigDecimal.valueOf(gFailCount + startCountStatisticsDTO.getTotalGCount() == 0 ? BigDecimal.ZERO.doubleValue() : new BigDecimal(startCountStatisticsDTO.getTotalGCount()).divide(new BigDecimal(gFailCount + startCountStatisticsDTO.getTotalGCount()), 2, RoundingMode.HALF_UP).doubleValue()).multiply(new BigDecimal(100)).doubleValue();
            double pPercent = BigDecimal.valueOf(pFailCount + startCountStatisticsDTO.getTotalPCount() == 0 ? BigDecimal.ZERO.doubleValue() : new BigDecimal(startCountStatisticsDTO.getTotalPCount()).divide(new BigDecimal(pFailCount + startCountStatisticsDTO.getTotalPCount()), 2, RoundingMode.HALF_UP).doubleValue()).multiply(new BigDecimal(100)).doubleValue();
            double pcPercent = BigDecimal.valueOf(pcFailCount + startCountStatisticsDTO.getTotalPCCount() == 0 ? BigDecimal.ZERO.doubleValue() : new BigDecimal(startCountStatisticsDTO.getTotalPCCount()).divide(new BigDecimal(pcFailCount + startCountStatisticsDTO.getTotalPCCount()), 2, RoundingMode.HALF_UP).doubleValue()).multiply(new BigDecimal(100)).doubleValue();
            startCountStatisticsDTO.setGSuccessPercent(gPercent);
            startCountStatisticsDTO.setPSuccessPercent(pPercent);
            startCountStatisticsDTO.setPcSuccessPercent(pcPercent);
        }
        return startCountStatisticsDTO;
    }

    /**
     * 导入历史数据，需要导入
     *
     * @param file
     */
    @Transactional(rollbackFor = Exception.class)
    public void importMorningPaperHistoryData(MultipartFile file, User user) throws Exception {
        ImportParams importParams = new ImportParams();
        List<MorningPaperExcelDTO> dtoList = ExcelImportUtil.importExcel(file.getInputStream(), MorningPaperExcelDTO.class, importParams);
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }
        log.info("导入的早报历史数据:{}", JSON.toJSONString(dtoList));
        //导入早报历史数据，之前日期有的删除
        List<Date> dateList = dtoList.stream().map(MorningPaperExcelDTO::getDate).collect(Collectors.toList());
        LambdaQueryChainWrapper<MorningPaperVariablesPo> wrapper = new LambdaQueryChainWrapper<>(morningPaperVariablesDao);
        List<MorningPaperVariablesPo> list = wrapper.in(CollectionUtils.isNotEmpty(dateList), MorningPaperVariablesPo::getDate, dateList)
                .list();
        LambdaQueryChainWrapper<MorningPaperHisPo> hisWrapper = new LambdaQueryChainWrapper<>(morningPaperHisDao);
        List<MorningPaperHisPo> hisPoList = hisWrapper.in(CollectionUtils.isNotEmpty(dateList), MorningPaperHisPo::getDate, dateList)
                .list();
        List<MorningPaperVariablesPo> morningPaperVariablesPoList = new ArrayList<>();
        List<MorningPaperHisPo> morningPaperHisPoList = new ArrayList<>();
        dtoList.forEach(morningPaperExcelDTO -> {
            MorningPaperHisPo morningPaperHisPo = buildMorningHisPo(morningPaperExcelDTO, user);
            morningPaperHisPoList.add(morningPaperHisPo);
            for (Field field : MorningPaperExcelDTO.class.getDeclaredFields()) {
                try {
                    field.setAccessible(true);
                    if ("date".equals(field.getName())) {
                        continue;
                    }
                    if (Objects.isNull(field.get(morningPaperExcelDTO))) {
                        throw new BusinessException(String.format("该字段为必填值:%s", field.getName()));
                    }
                    MorningPaperVariablesPo variablesPo = new MorningPaperVariablesPo();
                    variablesPo.setDate(DateTime.of(morningPaperExcelDTO.getDate()).toSqlDate());
                    variablesPo.setVariableName(field.getName());
                    variablesPo.setValue(String.valueOf(field.get(morningPaperExcelDTO)));
                    MorningPaperNormalVariableNames variableNames = MorningPaperNormalVariableNames.getByCode(variablesPo.getVariableName());
                    if (Objects.isNull(variableNames)) {
                        continue;
                    }
                    variablesPo.setDescription(variableNames.getDesc());
                    variablesPo.setMeteCode(variableNames.getMeteCode());
                    variablesPo.setMeteId(variableNames.getMeteId());
                    morningPaperVariablesPoList.add(variablesPo);
                } catch (IllegalAccessException e) {
                    log.info("处理异常:{}", e.getMessage());
                }
            }
        });
        if (CollectionUtils.isNotEmpty(list)) {
            log.info("删除早报变量:{}", JSON.toJSONString(list));
            morningPaperVariablesDao.deleteBatchIds(list.stream().map(MorningPaperVariablesPo::getId).collect(Collectors.toList()));
        }
        if (CollectionUtils.isNotEmpty(hisPoList)) {
            //删除t_morning_paper_his表中相同日期的
            log.info("删除早报历史:{}", JSON.toJSONString(hisPoList));
            morningPaperHisDao.deleteBatchIds(hisPoList.stream().map(MorningPaperHisPo::getId).collect(Collectors.toList()));
        }
        //保存早报变量数据
        log.info("保存早报变量历史数据:{}", JSON.toJSONString(morningPaperVariablesPoList));
        saveBatch(morningPaperVariablesPoList);
        //保存早报历史
        log.info("保存早报历史数据:{}", JSON.toJSONString(morningPaperHisPoList));
        morningPaperHisService.saveBatch(morningPaperHisPoList);
    }

    private static MorningPaperHisPo buildMorningHisPo(MorningPaperExcelDTO morningPaperExcelDTO, User user) {
        MorningPaperHisPo morningPaperHisPo = new MorningPaperHisPo();
        String machinePriority = StringUtils.isNotBlank(morningPaperExcelDTO.getMachinePriority()) ? morningPaperExcelDTO.getMachinePriority() : "";
        String machineWholePowerUpCount = morningPaperExcelDTO.getMachineWholePowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineWholePowerUpCount()) : "";
        String machineU01ConditionGPowerUpCount = morningPaperExcelDTO.getMachineU01ConditionGPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionGPowerUpCount()) : "";
        String machineU01ConditionGPowerUpHours = morningPaperExcelDTO.getMachineU01ConditionGPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionGPowerUpHours()) : "";
        String machineU02ConditionGPowerUpCount = morningPaperExcelDTO.getMachineU02ConditionGPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionGPowerUpCount()) : "";
        String machineU02ConditionGPowerUpHours = morningPaperExcelDTO.getMachineU02ConditionGPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionGPowerUpHours()) : "";
        String machineU03ConditionGPowerUpCount = morningPaperExcelDTO.getMachineU03ConditionGPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionGPowerUpCount()) : "";
        String machineU03ConditionGPowerUpHours = morningPaperExcelDTO.getMachineU03ConditionGPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionGPowerUpHours()) : "";
        String machineU04ConditionGPowerUpCount = morningPaperExcelDTO.getMachineU04ConditionGPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionGPowerUpCount()) : "";
        String machineU04ConditionGPowerUpHours = morningPaperExcelDTO.getMachineU04ConditionGPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionGPowerUpHours()) : "";

        String machineU01ConditionPPowerUpCount = morningPaperExcelDTO.getMachineU01ConditionPPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionPPowerUpCount()) : "";
        String machineU01ConditionPPowerUpHours = morningPaperExcelDTO.getMachineU01ConditionPPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionPPowerUpHours()) : "";
        String machineU02ConditionPPowerUpCount = morningPaperExcelDTO.getMachineU02ConditionPPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionPPowerUpCount()) : "";
        String machineU02ConditionPPowerUpHours = morningPaperExcelDTO.getMachineU02ConditionPPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionPPowerUpHours()) : "";
        String machineU03ConditionPPowerUpCount = morningPaperExcelDTO.getMachineU03ConditionPPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionPPowerUpCount()) : "";
        String machineU03ConditionPPowerUpHours = morningPaperExcelDTO.getMachineU03ConditionPPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionPPowerUpHours()) : "";
        String machineU04ConditionPPowerUpCount = morningPaperExcelDTO.getMachineU04ConditionPPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionPPowerUpCount()) : "";
        String machineU04ConditionPPowerUpHours = morningPaperExcelDTO.getMachineU04ConditionPPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionPPowerUpHours()) : "";

        String machineU01ConditionPCPowerUpCount = morningPaperExcelDTO.getMachineU01ConditionPCPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionPCPowerUpCount()) : "";
        String machineU01ConditionPCPowerUpHours = morningPaperExcelDTO.getMachineU01ConditionPCPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU01ConditionPCPowerUpHours()) : "";
        String machineU02ConditionPCPowerUpCount = morningPaperExcelDTO.getMachineU02ConditionPCPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionPCPowerUpCount()) : "";
        String machineU02ConditionPCPowerUpHours = morningPaperExcelDTO.getMachineU02ConditionPCPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU02ConditionPCPowerUpHours()) : "";
        String machineU03ConditionPCPowerUpCount = morningPaperExcelDTO.getMachineU03ConditionPCPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionPCPowerUpCount()) : "";
        String machineU03ConditionPCPowerUpHours = morningPaperExcelDTO.getMachineU03ConditionPCPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU03ConditionPCPowerUpHours()) : "";
        String machineU04ConditionPCPowerUpCount = morningPaperExcelDTO.getMachineU04ConditionPCPowerUpCount() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionPCPowerUpCount()) : "";
        String machineU04ConditionPCPowerUpHours = morningPaperExcelDTO.getMachineU04ConditionPCPowerUpHours() != null ? String.valueOf(morningPaperExcelDTO.getMachineU04ConditionPCPowerUpHours()) : "";

        String machinePowerUpInWholeYearCount = morningPaperExcelDTO.getMachinePowerUpInWholeYearCount() != null ? String.valueOf(morningPaperExcelDTO.getMachinePowerUpInWholeYearCount()) : "";
        String conditionGInWholeYearCount = morningPaperExcelDTO.getConditionGInWholeYearCount() != null ? String.valueOf(morningPaperExcelDTO.getConditionGInWholeYearCount()) : "";
        String conditionPInWholeYearCount = morningPaperExcelDTO.getConditionPInWholeYearCount() != null ? String.valueOf(morningPaperExcelDTO.getConditionPInWholeYearCount()) : "";
        String conditionPCInWholeYearCount = morningPaperExcelDTO.getConditionPCInWholeYearCount() != null ? String.valueOf(morningPaperExcelDTO.getConditionPCInWholeYearCount()) : "";

        String conditionGInWholeYearSuccessPercent = morningPaperExcelDTO.getConditionGInWholeYearSuccessPercent() != null ? String.valueOf(morningPaperExcelDTO.getConditionGInWholeYearSuccessPercent()) : "";
        String conditionPInWholeYearSuccessPercent = morningPaperExcelDTO.getConditionPInWholeYearSuccessPercent() != null ? String.valueOf(morningPaperExcelDTO.getConditionPInWholeYearSuccessPercent()) : "";
        String conditionPCInWholeYearSuccessPercent = morningPaperExcelDTO.getConditionPCInWholeYearSuccessPercent() != null ? String.valueOf(morningPaperExcelDTO.getConditionPCInWholeYearSuccessPercent()) : "";

        String waterLevelUpperReservoirMetres = morningPaperExcelDTO.getWaterLevelUpperReservoirMetres() != null ? String.valueOf(morningPaperExcelDTO.getWaterLevelUpperReservoirMetres()) : "";
        String waterLevelUnderReservoirMetres = morningPaperExcelDTO.getWaterLevelUnderReservoirMetres() != null ? String.valueOf(morningPaperExcelDTO.getWaterLevelUnderReservoirMetres()) : "";
        String waterLevelTotalStorageCubicMetres = morningPaperExcelDTO.getWaterLevelTotalStorageCubicMetres() != null ? String.valueOf(morningPaperExcelDTO.getWaterLevelTotalStorageCubicMetres()) : "";

        String waterBuildingInNormal = StringUtils.isNotBlank(morningPaperExcelDTO.getWaterBuildingInNormal()) ? morningPaperExcelDTO.getWaterBuildingInNormal() : "";
        String currentTimeOnGridEnergyTenThousandKwh = morningPaperExcelDTO.getCurrentTimeOnGridEnergyTenThousandKwh() != null ? String.valueOf(morningPaperExcelDTO.getCurrentTimeOnGridEnergyTenThousandKwh()) : "";
        String currentTimePowerConsumptionThousandKwh = morningPaperExcelDTO.getCurrentTimePowerConsumptionThousandKwh() != null ? String.valueOf(morningPaperExcelDTO.getCurrentTimePowerConsumptionThousandKwh()) : "";

        String thisYearPowerConsumptionOneHundredMillionKwh = morningPaperExcelDTO.getThisYearPowerConsumptionOneHundredMillionKwh() != null ? String.valueOf(morningPaperExcelDTO.getThisYearPowerConsumptionOneHundredMillionKwh()) : "";
        String thisYearOnGridEnergyOneHundredMillionKwh = morningPaperExcelDTO.getThisYearOnGridEnergyOneHundredMillionKwh() != null ? String.valueOf(morningPaperExcelDTO.getThisYearOnGridEnergyOneHundredMillionKwh()) : "";

        String detail = String.format("1.运行：机组优先权%s，共启动%s次。\n" +
                        "\n" +
                        "#1机组：G工况启动%s次共运行%sh，P工况启动%s次共运行%sh，PC工况启动%s次共运行%sh;\n" +
                        "\n" +
                        "#2机组：G工况启动%s次共运行%sh，P工况启动%s次共运行%sh，PC工况启动%s次共运行%sh;\n" +
                        "\n" +
                        "#3机组：G工况启动%s次共运行%sh，P工况启动%s次共运行%sh，PC工况启动%s次共运行%sh;\n" +
                        "\n" +
                        "#4机组：G工况启动%s次共运行%sh，P工况启动%s次共运行%sh，PC工况启动%s次共运行%sh;\n" +
                        "\n" +
                        "全年机组共启动%s次，G工况启动%s次，成功率%s%%；PC工况启动%s次，成功率%s%%，P工况启动%s次，成功率%s%%。\n" +
                        "\n" +
                        "2.水工：今日08:00，上库水位%sm，下库水位%sm，总蓄水量约%s万方，水工建筑物%s。\n" +
                        "\n" +
                        "3.电量：该时段上网电量%s万度，用网电量%s万度；2023年累计上网电量%s亿度，用网电量%s亿度。", machinePriority, machineWholePowerUpCount,
                machineU01ConditionGPowerUpCount, machineU01ConditionGPowerUpHours, machineU01ConditionPPowerUpCount, machineU01ConditionPPowerUpHours, machineU01ConditionPCPowerUpCount, machineU01ConditionPCPowerUpHours,
                machineU02ConditionGPowerUpCount, machineU02ConditionGPowerUpHours, machineU02ConditionPPowerUpCount, machineU02ConditionPPowerUpHours, machineU02ConditionPCPowerUpCount, machineU02ConditionPCPowerUpHours,
                machineU03ConditionGPowerUpCount, machineU03ConditionGPowerUpHours, machineU03ConditionPPowerUpCount, machineU03ConditionPPowerUpHours, machineU03ConditionPCPowerUpCount, machineU03ConditionPCPowerUpHours,
                machineU04ConditionGPowerUpCount, machineU04ConditionGPowerUpHours, machineU04ConditionPPowerUpCount, machineU04ConditionPPowerUpHours, machineU04ConditionPCPowerUpCount, machineU04ConditionPCPowerUpHours,
                machinePowerUpInWholeYearCount, conditionGInWholeYearCount, conditionGInWholeYearSuccessPercent, conditionPCInWholeYearCount, conditionPCInWholeYearSuccessPercent, conditionPInWholeYearCount, conditionPInWholeYearSuccessPercent,
                waterLevelUpperReservoirMetres, waterLevelUnderReservoirMetres, waterLevelTotalStorageCubicMetres, waterBuildingInNormal,
                currentTimeOnGridEnergyTenThousandKwh, currentTimePowerConsumptionThousandKwh, thisYearPowerConsumptionOneHundredMillionKwh, thisYearOnGridEnergyOneHundredMillionKwh);
        morningPaperHisPo.setDetail(detail);
        morningPaperHisPo.setDate(morningPaperExcelDTO.getDate());
        morningPaperHisPo.setReviewer(user.getUserName());
        morningPaperHisPo.setReviewed(1);
        morningPaperHisPo.setCreator(user.getUserName());
        morningPaperHisPo.setUpdater(user.getUserName());
        morningPaperHisPo.setCreateTime(new Date());
        morningPaperHisPo.setUpdateTime(new Date());
        return morningPaperHisPo;
    }
}
